package nxu.it.movieapi.service.mongo;

import nxu.it.api.model.*;
import nxu.it.api.service.MovieCastService;
import nxu.it.movieapi.Doc.CastDoc;
import nxu.it.movieapi.Doc.FilmographyDoc;
import nxu.it.movieapi.Doc.MovieDoc;
import nxu.it.movieapi.Doc.StaffDoc;
import nxu.it.movieapi.service.mapper.CastMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;

@Component
public class MovieCastServiceMongoImpl implements MovieCastService {

    @Autowired
    private MongoTemplate template;

    @Autowired
    private CastMapper castMapper;

    @Override
    public List<Cast> findCastByMovieId(@NotNull Integer movieId) {
        Query query = new Query(Criteria.where("_id").is(movieId));
        MovieDoc movieDoc = template.findOne(query, MovieDoc.class);
        List<Cast> castList = new ArrayList<>();
        if (movieDoc != null) {
            // Map actors and directors to Cast objects
            List<CastDoc> actorDocs = movieDoc.getActors();
            List<CastDoc> directorDocs = movieDoc.getDirectors();

            List<Cast> actors = castMapper.fromDocList(actorDocs);
            List<Cast> directors = castMapper.fromDocList(directorDocs);

            // Set role type IDs
            actors.forEach(cast -> cast.setRoleTypeId(CastRole.ACTOR.getId()));
            directors.forEach(cast -> cast.setRoleTypeId(CastRole.DIRECTOR.getId()));

            castList.addAll(directors);
            castList.addAll(actors);
        }
        return castList;
    }

    @Override
    public List<Cast> findCastByMovieIdAndRole(@NotNull Integer movieId, @NotNull CastRole role) {
        Query query = new Query(Criteria.where("_id").is(movieId));
        MovieDoc movieDoc = template.findOne(query, MovieDoc.class);
        List<Cast> castList = new ArrayList<>();
        if (movieDoc != null) {
            if (role == CastRole.ACTOR) {
                List<CastDoc> actorDocs = movieDoc.getActors();
                List<Cast> actors = castMapper.fromDocList(actorDocs);
                actors.forEach(cast -> cast.setRoleTypeId(CastRole.ACTOR.getId()));
                castList.addAll(actors);
            } else if (role == CastRole.DIRECTOR) {
                List<CastDoc> directorDocs = movieDoc.getDirectors();
                List<Cast> directors = castMapper.fromDocList(directorDocs);
                directors.forEach(cast -> cast.setRoleTypeId(CastRole.DIRECTOR.getId()));
                castList.addAll(directors);
            }
        }
        return castList;
    }

    @Override
    public List<Filmography> findMoviesByStaffId(@NotNull Integer staffId) {
        Query query = new Query(Criteria.where("_id").is(staffId));
        StaffDoc staffDoc = template.findOne(query, StaffDoc.class);
        List<Filmography> filmographyList = new ArrayList<>();
        if (staffDoc != null) {
            List<FilmographyDoc> directedDocs = staffDoc.getDirected();
            List<FilmographyDoc> actedDocs = staffDoc.getActed();

            List<Filmography> directed = castMapper.fromFilmographyDocList(directedDocs);
            List<Filmography> acted = castMapper.fromFilmographyDocList(actedDocs);

            // Set role type IDs
            directed.forEach(filmography -> filmography.setRoleTypeId(CastRole.DIRECTOR.getId()));
            acted.forEach(filmography -> filmography.setRoleTypeId(CastRole.ACTOR.getId()));

            filmographyList.addAll(directed);
            filmographyList.addAll(acted);
        }
        return filmographyList;
    }

    @Override
    public List<Filmography> findMoviesByStaffIdAndRole(@NotNull Integer staffId, @NotNull CastRole role) {
        Query query = new Query(Criteria.where("_id").is(staffId));
        StaffDoc staffDoc = template.findOne(query, StaffDoc.class);
        List<Filmography> filmographyList = new ArrayList<>();
        if (staffDoc != null) {
            if (role == CastRole.DIRECTOR) {
                List<FilmographyDoc> directedDocs = staffDoc.getDirected();
                List<Filmography> directed = castMapper.fromFilmographyDocList(directedDocs);
                directed.forEach(filmography -> filmography.setRoleTypeId(CastRole.DIRECTOR.getId()));
                filmographyList.addAll(directed);
            } else if (role == CastRole.ACTOR) {
                List<FilmographyDoc> actedDocs = staffDoc.getActed();
                List<Filmography> acted = castMapper.fromFilmographyDocList(actedDocs);
                acted.forEach(filmography -> filmography.setRoleTypeId(CastRole.ACTOR.getId()));
                filmographyList.addAll(acted);
            }
        }
        return filmographyList;
    }
}
